import { arrayMethods } from "../array";

class Observer {
  constructor(value) {
    //value可能是数组和对象
    // value.__ob__ = this;
    //所有的数据都加了__ob__;
    Object.defineProperty(value, "__ob__", {
      value: this,
      enumerable: false, // 不能被枚举，循环的时候找不到这个属性
      configurable: false, // 不能删除这个属性
    });
    if (Array.isArray(value)) {
      //  数组不用defineProperty
      //  push shift reverse sort 重写方法，更新逻辑
      Object.setPrototypeOf(value, arrayMethods); // 如果是数组改写方法为自己重写之后的方法
      this.observeArray(value); // Object.freeze();
    } else {
      this.walk(value);
    }
    //  需要对value属性重新定义 Object.defineProperty
  }

  observeArray(value) {
    for (let i in value) {
      observe(value[i]);
    }
  }
  // const arr = [1,10000];
  // push unshift sort
  // arr[0] = 'msg';

  walk(data) {
    Object.keys(data).forEach((key) => {
      //对象中的数据重新定义成响应式的
      defineReactive(data, key, data[key]);
    });
  }
}

function defineReactive(data, key, value) {
  // vue2数据嵌套不要太深，否则性能差
  // value可能还是对象
  observe(value); // 对结果递归
  Object.defineProperty(data, key, {
    get() {
      return value;
    },

    set(newValue) {
      if (newValue === value) return;
      observe(newValue);
      value = newValue;
      render();
    },
  });
}

export function observe(data) {
  // console.log(data);

  //  只能观测对象，非对象类型无法观测 如果不是对象直接return
  if (typeof data !== "object" || data === null) {
    return;
  }

  if (data.__ob__) return; // 如果被观测过了，直接return防止循环引用

  //  通过类实现对数据的观测
  //  类可以方便拓展，会产生实例，实例可以作为唯一标识
  return new Observer(data);
}
